package mz.co.research.util.importer;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import mz.co.framework.error.ISystemException;
import mz.co.framework.error.SystemException;
import mz.co.frameworks.loader.Cell;
import mz.co.frameworks.loader.DataSet;
import mz.co.frameworks.loader.Row;
import mz.co.frameworks.loader.Workbook;
import mz.co.research.server.mvc.model.dao.jpa.AnswerTypeJpaDao;
import mz.co.research.shared.model.Answer;
import mz.co.research.shared.model.AnswerDomain;
import mz.co.research.shared.model.AnswerDomainItem;
import mz.co.research.shared.model.Form;
import mz.co.research.shared.model.Question;
import mz.co.research.shared.model.Research;
import mz.co.research.util.parser.metadata.MetaAnswer;
import mz.co.research.util.parser.metadata.MetaAnswerDomain;
import mz.co.research.util.parser.metadata.MetaAnswerDomainItem;
import mz.co.research.util.parser.metadata.MetaForm;
import mz.co.research.util.parser.metadata.MetaQuestion;
import mz.co.research.util.parser.metadata.MetaResearch;

import org.apache.commons.lang.StringUtils;

public class ResearchImporter {

	private AnswerTypeJpaDao answerTypeJpaDao;

	public ResearchImporter(AnswerTypeJpaDao answerTypeJpaDao) {
		this.answerTypeJpaDao = answerTypeJpaDao;
	}

	/**
	 * Prepare the Research with all Meta Data informations.
	 * 
	 * @param metaResearch
	 *            Research Meta Data
	 * @param dataSets
	 *            Data Set (all answers)
	 * @return return Research with all information provided by Meta Data.
	 * @throws SystemException
	 *             Unexpected Error
	 */
	public Research load(MetaResearch metaResearch, Workbook workbook)
			throws SystemException {

		// Percorrendo Datas e realizando a montagem do Research baseado
		// nas regras definidas no Research Meta Data.

		Research research = new Research();
		research.setCode(metaResearch.getCode());
		research.setDescription(metaResearch.getDescription());

		List<MetaForm> metaForms = metaResearch.getForms();

		for (MetaForm metaForm : metaForms) {

			// Cada Dataset representa um Form.
			Form form = new Form();
			form.setResearch(research);

			form.setCode(metaForm.getCode());
			form.setDescription(metaForm.getDescription());

			// Baseado no Meta Data do Formulario montaremos juntamente com o
			// DataSet as Questoes
			List<MetaQuestion> metaQuestions = metaForm.getQuestions();

			for (MetaQuestion metaQuestion : metaQuestions) {
				Question question = new Question();
				question.setForm(form);
				question.setDescription(metaQuestion.getDescription());
				question.setAnswerType(answerTypeJpaDao.findByType(metaQuestion
						.getAnswerType()));

				MetaAnswerDomain metaAnswerDomain = metaQuestion
						.getAnswerDomain();

				if (metaAnswerDomain != null) {
					AnswerDomain answerDomain = new AnswerDomain();
					answerDomain.setCode(metaAnswerDomain.getCode());
					answerDomain.setDescription(metaAnswerDomain
							.getDescription());

					List<MetaAnswerDomainItem> metaAnswerDomainItems = metaAnswerDomain
							.getAnswerDomainItems();

					long order = 1;
					for (MetaAnswerDomainItem metaAnswerDomainItem : metaAnswerDomainItems) {
						AnswerDomainItem answerDomainItem = new AnswerDomainItem();
						answerDomainItem
								.setCode(metaAnswerDomainItem.getCode());
						answerDomainItem.setDescription(metaAnswerDomainItem
								.getDescription());
						answerDomainItem.setOrder(order++);
						answerDomain.addItem(answerDomainItem);
					}

					question.setAnswerDomain(answerDomain);

					// Adicionando o Universo de Respostas Obtidas no data Set
					// de acordo com o MetaData da Resposta (onde será
					// localizada a resposta)
					addAnswers(metaQuestion.getAnswer(), metaAnswerDomain,
							question, workbook.getDataSet(metaForm.getCode()));

				}

				form.addQuestion(question);
			}

			research.addForm(form);

		}

		return research;

	}

	private void addAnswers(MetaAnswer metaAnswer,
			MetaAnswerDomain metaAnswerDomain, Question question,
			DataSet dataSet) throws SystemException {

		String[] cordinations = metaAnswer.getFetch().split(",");

		for (String c : cordinations) {

			String cordination = StringUtils.trim(c);

			for (String data : getData(dataSet, cordination)) {
				Answer answer = new Answer();
				answer.setText(validate(metaAnswerDomain, data));
				question.addAnswer(answer);
			}

		}

	}

	private Collection<String> getData(DataSet dataSet, String cordination)
			throws SystemException {

		Collection<String> datas = new ArrayList<String>();

		// C0R0 or C0R*
		int cini = cordination.indexOf("C") + 1;
		int cend = cordination.indexOf("R");

		int rini = cordination.indexOf("R") + 1;
		int rend = cordination.length();

		// Se Linha (R*) indica que todos os resultados obtidos na
		// coluna compreendem a resposta para a questão.
		String ccol = cordination.substring(cini, cend);
		String crow = cordination.substring(rini, rend);

		if (crow.equals("*")) {

			for (Row row : dataSet.getRows()) {
				datas.add(row.getCell("C" + ccol + row.getName()).getData());
			}

		} else {

			Cell cell = dataSet.getRow("R" + crow).getCell(
					"C" + ccol + "R" + crow);

			// Procurar a celula. Não dá para usar as coordenadas, pois
			// O Loader do Excel simplesmente ignora células em branco.
			datas.add(cell == null ? StringUtils.EMPTY : cell.getData());

		}

		return datas;
	}

	private String validate(MetaAnswerDomain metaAnswerDomain, String data)
			throws SystemException {

		for (MetaAnswerDomainItem metaAnswerDomainItem : metaAnswerDomain
				.getAnswerDomainItems()) {
			if (metaAnswerDomainItem.getCode().equals(data)) {
				throw new SystemException(ISystemException.META_DATA_VALIDATION);
			}
		}

		return data;
	}
}
